/* XXX does not use built-in detection function! XXX
alert tcp $EXTERNAL_NET $HTTP_PORTS -> $HOME_NET any (msg:"WEB-CLIENT Winamp MAKI parsing integer overflow attempt"; flowbits:isset,file.maki; flow:to_client,established; content:"FG|03 04 17 00 00 00|"; byte_jump:4,0,relative,multiplier 16,little; byte_jump:4,0,relative,multiplier 14,little; metadata:policy balanced-ips drop, policy security-ips drop, service http; classtype:attempted-user;)
*/
/*
 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */


#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

//#define DEBUG 1
#ifdef DEBUG
#define DEBUG_WRAP(code) code
#else
#define DEBUG_WRAP(code)
#endif

/* declare detection functions */
int rule15433eval(void *p);

/* declare rule data structures */
/* precompile the stuff that needs pre-compiled */
/* flowbits:isset "file.maki"; */
static FlowBitsInfo rule15433flowbits0 =
{
    "file.maki",
    FLOWBIT_ISSET,
    0,
};

static RuleOption rule15433option0 =
{
    OPTION_TYPE_FLOWBIT,
    {
        &rule15433flowbits0
    }
};
/* flow:established, to_client; */
static FlowFlags rule15433flow1 = 
{
    FLOW_ESTABLISHED|FLOW_TO_CLIENT
};

static RuleOption rule15433option1 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule15433flow1
    }
};
// content:"FG|03 04 17 00 00 00|", depth 0; 
static ContentInfo rule15433content2 = 
{
    (uint8_t *) "FG|03 04 17 00 00 00|", /* pattern (now in snort content format) */
    0, /* depth */
    0, /* offset */
    CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule15433option2 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule15433content2
    }
};
/* byte_jump:size 4, multiplier 16, relative, endian little; */
static ByteData rule15433byte_jump3 = 
{
    4, /* size */
    0, /* operator, byte_jump doesn't use operator! */
    0, /* value, byte_jump doesn't use value! */
    0, /* offset */
    16, /* multiplier */
    BYTE_LITTLE_ENDIAN|CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED|EXTRACT_AS_BYTE /* flags */
};

static RuleOption rule15433option3 = 
{
    OPTION_TYPE_BYTE_JUMP,
    {
        &rule15433byte_jump3
    }
};
/* byte_jump:size 4, multiplier 14, relative, endian little; */
static ByteData rule15433byte_jump4 = 
{
    4, /* size */
    0, /* operator, byte_jump doesn't use operator! */
    0, /* value, byte_jump doesn't use value! */
    0, /* offset */
    14, /* multiplier */
    BYTE_LITTLE_ENDIAN|CONTENT_RELATIVE|CONTENT_BUF_NORMALIZED|EXTRACT_AS_BYTE /* flags */
};

static RuleOption rule15433option4 = 
{
    OPTION_TYPE_BYTE_JUMP,
    {
        &rule15433byte_jump4
    }
};

/* references for sid 15433 */
/* reference: bugtraq "35052"; */
static RuleReference rule15433ref1 = 
{
    "bugtraq", /* type */
    "35052" /* value */
};

/* reference: cve "2009-1831"; */
static RuleReference rule15433ref2 = 
{
    "cve", /* type */
    "2009-1831" /* value */
};

static RuleReference *rule15433refs[] =
{
    &rule15433ref1,
    &rule15433ref2,
    NULL
};
/* metadata for sid 15433 */
/* metadata:service http, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule15433service1 = 
{
    "service http"
};


//static RuleMetaData rule15433policy1 = 
//{
//    "policy balanced-ips drop"
//};
//
//static RuleMetaData rule15433policy2 = 
//{
//    "policy security-ips drop"
//};


static RuleMetaData *rule15433metadata[] =
{
    &rule15433service1,
//    &rule15433policy1,
//    &rule15433policy2,
    NULL
};

RuleOption *rule15433options[] =
{
    &rule15433option0,
    &rule15433option1,
    &rule15433option2,
    &rule15433option3,
    &rule15433option4,
    NULL
};

Rule rule15433 = {
   
   /* rule header, akin to => tcp any any -> any any               */{
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "$HTTP_PORTS", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "any", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       15433, /* sigid */
       7, /* revision */
   
       "attempted-user", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "FILE-OTHER Winamp MAKI parsing integer overflow attempt",     /* message */
       rule15433refs /* ptr to references */
       ,rule15433metadata
   },
   rule15433options, /* ptr to rule options */
   &rule15433eval, /* DO NOT use the built in detection function */
   0 /* am I initialized yet? */
};

/* test a block that includes array of string structures */
int rule15433eval_stringblock(const uint8_t **cursor_normal, const uint8_t *end_of_payload)
{
    const uint8_t *cursor_temp;
    uint32_t       str_count, i;  // the number of function names, the number of strings
    uint16_t       str_len;  // the length of function name, the length of string

    DEBUG_WRAP(const char *name="rule15433eval";)
      
    cursor_temp = *cursor_normal;
      
    if (cursor_temp + 4 < end_of_payload)
    {
        str_count = read_little_32(cursor_temp);
                     
        DEBUG_WRAP(printf("%s: num of strings 0x%08x\n", name, str_count);) 
        cursor_temp += 4;
                    
        for (i = 0; (i < str_count) && (cursor_temp + 6 <= end_of_payload); i++)
        {
            cursor_temp += 4;         // jump to the string length field
            str_len = read_little_16(cursor_temp);
            DEBUG_WRAP(printf("%s: length of string 0x%04x\n", name, str_len);)
    
            if (str_len >= 0x8000) // malicious condition
                return RULE_MATCH;

            cursor_temp += str_len + 2;                        
        }
    }

    *cursor_normal = cursor_temp;
    
    return RULE_NOMATCH;
}

/* detection functions */
int rule15433eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *beg_of_payload, *end_of_payload;
    int result;  // result returned from sub-function

    DEBUG_WRAP(const char *name="rule15433eval";)
    DEBUG_WRAP(printf("%s: enter\n", name);)
    
    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flowbits:isset "file.maki";
    if (processFlowbits(p, rule15433options[0]->option_u.flowBit) > 0) {
            // flow:established, to_client;
        if (checkFlow(p, rule15433options[1]->option_u.flowFlags) > 0 ) {
            // content:"FG|03 04 17 00 00 00|", depth 0;
            if (contentMatch(p, rule15433options[2]->option_u.content, &cursor_normal) > 0) {
                // byte_jump:size 4, multiplier 16, relative, endian little;
                if (byteJump(p, rule15433options[3]->option_u.byte, &cursor_normal) > 0) {

                    DEBUG_WRAP(printf("%s: \"FG|03 04 17 00 00 00|\" found \n", name);)
                    if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                        return RULE_NOMATCH;

                    // check function names
                    result = rule15433eval_stringblock(&cursor_normal, end_of_payload);
                    
                    if (result == RULE_MATCH)
                        return RULE_MATCH;

                    // skip the data block 
                    // byte_jump:size 4, multiplier 14, relative, endian little; 
                    if (byteJump(p, rule15433options[4]->option_u.byte, &cursor_normal) > 0)
                    {
                        // check general strings. e.g. menu captions
                        result = rule15433eval_stringblock(&cursor_normal, end_of_payload);
                        return result;
                    }                    
                }
            }
        }
    }
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule15433,
    NULL
};
*/
